// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie.network.packets;

import java.nio.ByteBuffer;
import java.util.HashMap;
import zombie.ai.states.ClimbDownSheetRopeState;
import zombie.ai.states.ClimbSheetRopeState;
import zombie.ai.states.FishingState;
import zombie.ai.states.SmashWindowState;
import zombie.characters.IsoGameCharacter;
import zombie.characters.IsoPlayer;
import zombie.characters.IsoZombie;
import zombie.characters.NetworkPlayerVariables;
import zombie.characters.CharacterTimedActions.BaseAction;
import zombie.core.Core;
import zombie.core.network.ByteBufferWriter;
import zombie.core.raknet.UdpConnection;
import zombie.debug.DebugLog;
import zombie.debug.DebugType;
import zombie.iso.IsoDirections;
import zombie.iso.IsoGridSquare;
import zombie.iso.IsoObject;
import zombie.iso.SpriteDetails.IsoFlagType;
import zombie.iso.objects.IsoThumpable;
import zombie.iso.objects.IsoWindow;
import zombie.iso.objects.IsoWindowFrame;
import zombie.network.GameClient;
import zombie.network.GameServer;
import zombie.util.StringUtils;
import zombie.vehicles.BaseVehicle;
import zombie.vehicles.VehicleManager;
import zombie.vehicles.VehiclePart;
import zombie.vehicles.VehicleWindow;

public class EventPacket implements INetworkPacket {
    public static final int MAX_PLAYER_EVENTS = 10;
    private static final long EVENT_TIMEOUT = 5000L;
    private static final short EVENT_FLAGS_VAULT_OVER_SPRINT = 1;
    private static final short EVENT_FLAGS_VAULT_OVER_RUN = 2;
    private static final short EVENT_FLAGS_BUMP_FALL = 4;
    private static final short EVENT_FLAGS_BUMP_STAGGERED = 8;
    private static final short EVENT_FLAGS_ACTIVATE_ITEM = 16;
    private static final short EVENT_FLAGS_CLIMB_SUCCESS = 32;
    private static final short EVENT_FLAGS_CLIMB_STRUGGLE = 64;
    private static final short EVENT_FLAGS_BUMP_FROM_BEHIND = 128;
    private static final short EVENT_FLAGS_BUMP_TARGET_TYPE = 256;
    private static final short EVENT_FLAGS_PRESSED_MOVEMENT = 512;
    private static final short EVENT_FLAGS_PRESSED_CANCEL_ACTION = 1024;
    private static final short EVENT_FLAGS_SMASH_CAR_WINDOW = 2048;
    private static final short EVENT_FLAGS_FITNESS_FINISHED = 4096;
    private short id;
    public float x;
    public float y;
    public float z;
    private byte eventID;
    private String type1;
    private String type2;
    private String type3;
    private String type4;
    private float strafeSpeed;
    private float walkSpeed;
    private float walkInjury;
    private int booleanVariables;
    private short flags;
    private IsoPlayer player;
    private EventPacket.EventType event;
    private long timestamp;

    @Override
    public String getDescription() {
        return "[ player="
            + this.id
            + " \""
            + (this.player == null ? "?" : this.player.getUsername())
            + "\" | name=\""
            + (this.event == null ? "?" : this.event.name())
            + "\" | pos=( "
            + this.x
            + " ; "
            + this.y
            + " ; "
            + this.z
            + " ) | type1=\""
            + this.type1
            + "\" | type2=\""
            + this.type2
            + "\" | type3=\""
            + this.type3
            + "\" | type4=\""
            + this.type4
            + "\" | flags="
            + this.flags
            + "\" | variables="
            + this.booleanVariables
            + " ]";
    }

    @Override
    public boolean isConsistent() {
        boolean _boolean = this.player != null && this.event != null;
        if (!_boolean && Core.bDebug) {
            DebugLog.log(DebugType.Multiplayer, "[Event] is not consistent " + this.getDescription());
        }

        return _boolean;
    }

    @Override
    public void parse(ByteBuffer b, UdpConnection connection) {
        this.id = b.getShort();
        this.x = b.getFloat();
        this.y = b.getFloat();
        this.z = b.getFloat();
        this.eventID = b.get();
        this.type1 = zombie.GameWindow.ReadString(b);
        this.type2 = zombie.GameWindow.ReadString(b);
        this.type3 = zombie.GameWindow.ReadString(b);
        this.type4 = zombie.GameWindow.ReadString(b);
        this.strafeSpeed = b.getFloat();
        this.walkSpeed = b.getFloat();
        this.walkInjury = b.getFloat();
        this.booleanVariables = b.getInt();
        this.flags = b.getShort();
        if (this.eventID >= 0 && this.eventID < EventPacket.EventType.values().length) {
            this.event = EventPacket.EventType.values()[this.eventID];
        } else {
            DebugLog.Multiplayer.warn("Unknown event=" + this.eventID);
            this.event = null;
        }

        if (GameServer.bServer) {
            this.player = (IsoPlayer)GameServer.IDToPlayerMap.get(this.id);
        } else if (GameClient.bClient) {
            this.player = (IsoPlayer)GameClient.IDToPlayerMap.get(this.id);
        } else {
            this.player = null;
        }

        this.timestamp = System.currentTimeMillis() + 5000L;
    }

    @Override
    public void write(ByteBufferWriter b) {
        b.putShort(this.id);
        b.putFloat(this.x);
        b.putFloat(this.y);
        b.putFloat(this.z);
        b.putByte(this.eventID);
        b.putUTF(this.type1);
        b.putUTF(this.type2);
        b.putUTF(this.type3);
        b.putUTF(this.type4);
        b.putFloat(this.strafeSpeed);
        b.putFloat(this.walkSpeed);
        b.putFloat(this.walkInjury);
        b.putInt(this.booleanVariables);
        b.putShort(this.flags);
    }

    public boolean isRelevant(UdpConnection connection) {
        return connection.RelevantTo(this.x, this.y);
    }

    public boolean isMovableEvent() {
        return !this.isConsistent()
            ? false
            : EventPacket.EventType.EventClimbFence.equals(this.event) || EventPacket.EventType.EventFallClimb.equals(this.event);
    }

    private boolean requireNonMoving() {
        return this.isConsistent()
            && (
                EventPacket.EventType.EventClimbWindow.equals(this.event)
                    || EventPacket.EventType.EventClimbFence.equals(this.event)
                    || EventPacket.EventType.EventClimbDownRope.equals(this.event)
                    || EventPacket.EventType.EventClimbRope.equals(this.event)
                    || EventPacket.EventType.EventClimbWall.equals(this.event)
            );
    }

    private IsoWindow getWindow(IsoPlayer isoPlayer) {
        for (IsoDirections isoDirections : IsoDirections.values()) {
            IsoObject isoObject = isoPlayer.getContextDoorOrWindowOrWindowFrame(isoDirections);
            if (isoObject instanceof IsoWindow) {
                return (IsoWindow)isoObject;
            }
        }

        return null;
    }

    private IsoObject getObject(IsoPlayer isoPlayer) {
        for (IsoDirections isoDirections : IsoDirections.values()) {
            IsoObject isoObject = isoPlayer.getContextDoorOrWindowOrWindowFrame(isoDirections);
            if (isoObject instanceof IsoWindow || isoObject instanceof IsoThumpable || IsoWindowFrame.isWindowFrame(isoObject)) {
                return isoObject;
            }
        }

        return null;
    }

    private IsoDirections checkCurrentIsEventGridSquareFence(IsoPlayer isoPlayer) {
        IsoGridSquare isoGridSquare0 = isoPlayer.getCell().getGridSquare((double)this.x, (double)this.y, (double)this.z);
        IsoGridSquare isoGridSquare1 = isoPlayer.getCell().getGridSquare((double)this.x, (double)(this.y + 1.0F), (double)this.z);
        IsoGridSquare isoGridSquare2 = isoPlayer.getCell().getGridSquare((double)(this.x + 1.0F), (double)this.y, (double)this.z);
        IsoDirections isoDirections;
        if (isoGridSquare0 != null && isoGridSquare0.Is(IsoFlagType.HoppableN)) {
            isoDirections = IsoDirections.N;
        } else if (isoGridSquare0 != null && isoGridSquare0.Is(IsoFlagType.HoppableW)) {
            isoDirections = IsoDirections.W;
        } else if (isoGridSquare1 != null && isoGridSquare1.Is(IsoFlagType.HoppableN)) {
            isoDirections = IsoDirections.S;
        } else if (isoGridSquare2 != null && isoGridSquare2.Is(IsoFlagType.HoppableW)) {
            isoDirections = IsoDirections.E;
        } else {
            isoDirections = IsoDirections.Max;
        }

        return isoDirections;
    }

    public boolean isTimeout() {
        return System.currentTimeMillis() > this.timestamp;
    }

    public void tryProcess() {
        if (this.isConsistent()) {
            if (this.player.networkAI.events.size() < 10) {
                this.player.networkAI.events.add(this);
            } else {
                DebugLog.Multiplayer.warn("Event skipped: " + this.getDescription());
            }
        }
    }

    public boolean process(IsoPlayer _player) {
        boolean _boolean = false;
        if (this.isConsistent()) {
            _player.overridePrimaryHandModel = null;
            _player.overrideSecondaryHandModel = null;
            if (_player.getCurrentSquare() == _player.getCell().getGridSquare((double)this.x, (double)this.y, (double)this.z) && !_player.isPlayerMoving()
                || !this.requireNonMoving()) {
                switch (this.event) {
                    case EventSetActivatedPrimary:
                        if (_player.getPrimaryHandItem() != null && _player.getPrimaryHandItem().canEmitLight()) {
                            _player.getPrimaryHandItem().setActivatedRemote((this.flags & 16) != 0);
                            _boolean = true;
                        }
                        break;
                    case EventSetActivatedSecondary:
                        if (_player.getSecondaryHandItem() != null && _player.getSecondaryHandItem().canEmitLight()) {
                            _player.getSecondaryHandItem().setActivatedRemote((this.flags & 16) != 0);
                            _boolean = true;
                        }
                        break;
                    case EventFallClimb:
                        _player.setVariable("ClimbFenceOutcome", "fall");
                        _player.setVariable("BumpDone", true);
                        _player.setFallOnFront(true);
                        _boolean = true;
                        break;
                    case collideWithWall:
                        _player.setCollideType(this.type1);
                        _player.actionContext.reportEvent("collideWithWall");
                        _boolean = true;
                        break;
                    case EventFishing:
                        _player.setVariable("FishingStage", this.type1);
                        if (!FishingState.instance().equals(_player.getCurrentState())) {
                            _player.setVariable("forceGetUp", true);
                            _player.actionContext.reportEvent("EventFishing");
                        }

                        _boolean = true;
                        break;
                    case EventFitness:
                        _player.setVariable("ExerciseType", this.type1);
                        _player.setVariable("FitnessFinished", false);
                        _player.actionContext.reportEvent("EventFitness");
                        _boolean = true;
                        break;
                    case EventUpdateFitness:
                        _player.clearVariable("ExerciseHand");
                        _player.setVariable("ExerciseType", this.type2);
                        if (!StringUtils.isNullOrEmpty(this.type1)) {
                            _player.setVariable("ExerciseHand", this.type1);
                        }

                        _player.setFitnessSpeed();
                        if ((this.flags & 4096) != 0) {
                            _player.setVariable("ExerciseStarted", false);
                            _player.setVariable("ExerciseEnded", true);
                        }

                        _player.setPrimaryHandItem(null);
                        _player.setSecondaryHandItem(null);
                        _player.overridePrimaryHandModel = null;
                        _player.overrideSecondaryHandModel = null;
                        _player.overridePrimaryHandModel = this.type3;
                        _player.overrideSecondaryHandModel = this.type4;
                        _player.resetModelNextFrame();
                        _boolean = true;
                        break;
                    case EventEmote:
                        _player.setVariable("emote", this.type1);
                        _player.actionContext.reportEvent("EventEmote");
                        _boolean = true;
                        break;
                    case EventSitOnGround:
                        _player.actionContext.reportEvent("EventSitOnGround");
                        _boolean = true;
                        break;
                    case EventClimbRope:
                        _player.climbSheetRope();
                        _boolean = true;
                        break;
                    case EventClimbDownRope:
                        _player.climbDownSheetRope();
                        _boolean = true;
                        break;
                    case EventClimbFence:
                        IsoDirections isoDirections0 = this.checkCurrentIsEventGridSquareFence(_player);
                        if (isoDirections0 != IsoDirections.Max) {
                            _player.climbOverFence(isoDirections0);
                            if (_player.isSprinting()) {
                                _player.setVariable("VaultOverSprint", true);
                            }

                            if (_player.isRunning()) {
                                _player.setVariable("VaultOverRun", true);
                            }

                            _boolean = true;
                        }
                        break;
                    case EventClimbWall:
                        _player.setClimbOverWallStruggle((this.flags & 64) != 0);
                        _player.setClimbOverWallSuccess((this.flags & 32) != 0);

                        for (IsoDirections isoDirections1 : IsoDirections.values()) {
                            if (_player.climbOverWall(isoDirections1)) {
                                return true;
                            }
                        }
                        break;
                    case EventClimbWindow:
                        IsoObject isoObject = this.getObject(_player);
                        if (isoObject instanceof IsoWindow) {
                            _player.climbThroughWindow((IsoWindow)isoObject);
                            _boolean = true;
                        } else if (isoObject instanceof IsoThumpable) {
                            _player.climbThroughWindow((IsoThumpable)isoObject);
                            _boolean = true;
                        }

                        if (IsoWindowFrame.isWindowFrame(isoObject)) {
                            _player.climbThroughWindowFrame(isoObject);
                            _boolean = true;
                        }
                        break;
                    case EventOpenWindow:
                        IsoWindow isoWindow2 = this.getWindow(_player);
                        if (isoWindow2 != null) {
                            _player.openWindow(isoWindow2);
                            _boolean = true;
                        }
                        break;
                    case EventCloseWindow:
                        IsoWindow isoWindow1 = this.getWindow(_player);
                        if (isoWindow1 != null) {
                            _player.closeWindow(isoWindow1);
                            _boolean = true;
                        }
                        break;
                    case EventSmashWindow:
                        if ((this.flags & 2048) != 0) {
                            BaseVehicle baseVehicle = VehicleManager.instance.getVehicleByID(Short.parseShort(this.type1));
                            if (baseVehicle != null) {
                                VehiclePart vehiclePart = baseVehicle.getPartById(this.type2);
                                if (vehiclePart != null) {
                                    VehicleWindow vehicleWindow = vehiclePart.getWindow();
                                    if (vehicleWindow != null) {
                                        _player.smashCarWindow(vehiclePart);
                                        _boolean = true;
                                    }
                                }
                            }
                        } else {
                            IsoWindow isoWindow0 = this.getWindow(_player);
                            if (isoWindow0 != null) {
                                _player.smashWindow(isoWindow0);
                                _boolean = true;
                            }
                        }
                        break;
                    case wasBumped:
                        _player.setBumpDone(false);
                        _player.setVariable("BumpFallAnimFinished", false);
                        _player.setBumpType(this.type1);
                        _player.setBumpFallType(this.type2);
                        _player.setBumpFall((this.flags & 4) != 0);
                        _player.setBumpStaggered((this.flags & 8) != 0);
                        _player.reportEvent("wasBumped");
                        if (!StringUtils.isNullOrEmpty(this.type3) && !StringUtils.isNullOrEmpty(this.type4)) {
                            IsoGameCharacter isoGameCharacter = null;
                            if ((this.flags & 256) != 0) {
                                isoGameCharacter = GameClient.IDToZombieMap.get(Short.parseShort(this.type3));
                            } else {
                                isoGameCharacter = (IsoGameCharacter)GameClient.IDToPlayerMap.get(Short.parseShort(this.type3));
                            }

                            if (isoGameCharacter != null) {
                                isoGameCharacter.setBumpType(this.type4);
                                isoGameCharacter.setHitFromBehind((this.flags & 128) != 0);
                            }
                        }

                        _boolean = true;
                        break;
                    case EventOverrideItem:
                        if (_player.getNetworkCharacterAI().getAction() != null) {
                            _player.getNetworkCharacterAI().setOverride(true, this.type1, this.type2);
                        }

                        _boolean = true;
                        break;
                    case ChargeSpearConnect:
                        _boolean = true;
                        break;
                    case Update:
                        _player.networkAI.setPressedMovement((this.flags & 512) != 0);
                        _player.networkAI.setPressedCancelAction((this.flags & 1024) != 0);
                        _boolean = true;
                        break;
                    case Unknown:
                    default:
                        DebugLog.Multiplayer.warn("[Event] unknown: " + this.getDescription());
                        _boolean = true;
                }
            }
        }

        return _boolean;
    }

    public boolean set(IsoPlayer _player, String eventName) {
        boolean _boolean = false;
        this.player = _player;
        this.id = _player.getOnlineID();
        this.x = _player.getX();
        this.y = _player.getY();
        this.z = _player.getZ();
        this.type1 = null;
        this.type2 = null;
        this.type3 = null;
        this.type4 = null;
        this.booleanVariables = NetworkPlayerVariables.getBooleanVariables(_player);
        this.strafeSpeed = _player.getVariableFloat("StrafeSpeed", 1.0F);
        this.walkSpeed = _player.getVariableFloat("WalkSpeed", 1.0F);
        this.walkInjury = _player.getVariableFloat("WalkInjury", 0.0F);
        this.flags = 0;

        for (EventPacket.EventType eventType : EventPacket.EventType.values()) {
            if (eventType.name().equals(eventName)) {
                this.event = eventType;
                this.eventID = (byte)eventType.ordinal();
                switch (eventType) {
                    case EventSetActivatedPrimary:
                        this.flags = (short)(this.flags | (_player.getPrimaryHandItem().isActivated() ? 16 : 0));
                        break;
                    case EventSetActivatedSecondary:
                        this.flags = (short)(this.flags | (_player.getSecondaryHandItem().isActivated() ? 16 : 0));
                    case EventFallClimb:
                    case EventSitOnGround:
                    case EventClimbRope:
                    case EventClimbDownRope:
                    case EventClimbWindow:
                    case EventOpenWindow:
                    case EventCloseWindow:
                    case ChargeSpearConnect:
                        break;
                    case collideWithWall:
                        this.type1 = _player.getCollideType();
                        break;
                    case EventFishing:
                        this.type1 = _player.getVariableString("FishingStage");
                        break;
                    case EventFitness:
                        this.type1 = _player.getVariableString("ExerciseType");
                        break;
                    case EventUpdateFitness:
                        this.type1 = _player.getVariableString("ExerciseHand");
                        this.type2 = _player.getVariableString("ExerciseType");
                        if (_player.getPrimaryHandItem() != null) {
                            this.type3 = _player.getPrimaryHandItem().getStaticModel();
                        }

                        if (_player.getSecondaryHandItem() != null && _player.getSecondaryHandItem() != _player.getPrimaryHandItem()) {
                            this.type4 = _player.getSecondaryHandItem().getStaticModel();
                        }

                        this.flags = (short)(this.flags | (_player.getVariableBoolean("FitnessFinished") ? 4096 : 0));
                        break;
                    case EventEmote:
                        this.type1 = _player.getVariableString("emote");
                        break;
                    case EventClimbFence:
                        if (_player.getVariableBoolean("VaultOverRun")) {
                            this.flags = (short)(this.flags | 2);
                        }

                        if (_player.getVariableBoolean("VaultOverSprint")) {
                            this.flags = (short)(this.flags | 1);
                        }
                        break;
                    case EventClimbWall:
                        this.flags = (short)(this.flags | (_player.isClimbOverWallSuccess() ? 32 : 0));
                        this.flags = (short)(this.flags | (_player.isClimbOverWallStruggle() ? 64 : 0));
                        break;
                    case EventSmashWindow:
                        HashMap hashMap = _player.getStateMachineParams(SmashWindowState.instance());
                        if (hashMap.get(1) instanceof BaseVehicle && hashMap.get(2) instanceof VehiclePart) {
                            BaseVehicle baseVehicle = (BaseVehicle)hashMap.get(1);
                            VehiclePart vehiclePart = (VehiclePart)hashMap.get(2);
                            this.flags = (short)(this.flags | 2048);
                            this.type1 = String.valueOf(baseVehicle.getId());
                            this.type2 = vehiclePart.getId();
                        }
                        break;
                    case wasBumped:
                        this.type1 = _player.getBumpType();
                        this.type2 = _player.getBumpFallType();
                        this.flags = (short)(this.flags | (_player.isBumpFall() ? 4 : 0));
                        this.flags = (short)(this.flags | (_player.isBumpStaggered() ? 8 : 0));
                        if (_player.getBumpedChr() != null) {
                            this.type3 = String.valueOf(_player.getBumpedChr().getOnlineID());
                            this.type4 = _player.getBumpedChr().getBumpType();
                            this.flags = (short)(this.flags | (_player.isHitFromBehind() ? 128 : 0));
                            if (_player.getBumpedChr() instanceof IsoZombie) {
                                this.flags = (short)(this.flags | 256);
                            }
                        }
                        break;
                    case EventOverrideItem:
                        if (_player.getNetworkCharacterAI().getAction() == null) {
                            return false;
                        }

                        BaseAction baseAction = _player.getNetworkCharacterAI().getAction();
                        this.type1 = baseAction.getPrimaryHandItem() == null
                            ? baseAction.getPrimaryHandMdl()
                            : baseAction.getPrimaryHandItem().getStaticModel();
                        this.type2 = baseAction.getSecondaryHandItem() == null
                            ? baseAction.getSecondaryHandMdl()
                            : baseAction.getSecondaryHandItem().getStaticModel();
                        break;
                    case Update:
                        this.flags = (short)(this.flags | (_player.networkAI.isPressedMovement() ? 512 : 0));
                        this.flags = (short)(this.flags | (_player.networkAI.isPressedCancelAction() ? 1024 : 0));
                        break;
                    default:
                        DebugLog.Multiplayer.warn("[Event] unknown " + this.getDescription());
                        return false;
                }

                _boolean = !ClimbDownSheetRopeState.instance().equals(_player.getCurrentState())
                    && !ClimbSheetRopeState.instance().equals(_player.getCurrentState());
            }
        }

        return _boolean;
    }

    public static enum EventType {
        EventSetActivatedPrimary,
        EventSetActivatedSecondary,
        EventFishing,
        EventFitness,
        EventEmote,
        EventClimbFence,
        EventClimbDownRope,
        EventClimbRope,
        EventClimbWall,
        EventClimbWindow,
        EventOpenWindow,
        EventCloseWindow,
        EventSmashWindow,
        EventSitOnGround,
        wasBumped,
        collideWithWall,
        EventUpdateFitness,
        EventFallClimb,
        EventOverrideItem,
        ChargeSpearConnect,
        Update,
        Unknown;
    }
}
